/*
 * @Author: yehongbo 1394168736@qq.com
 * @Date: 2024-09-23 16:04:43
 * @LastEditors: yehongbo 1394168736@qq.com
 * @LastEditTime: 2024-09-23 17:49:31
 * @FilePath: \myWorkspace\react-basic\src\components\statesUse\index.jsx
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import { useState, useRef } from 'react';
// 相同位置的相同组件会使得 state 被保留下来
// 记住 对 React 来说重要的是组件在 UI 树中的位置,而不是在 JSX 中的位置！ 这个组件在 if 内外有两个return 语句，它们带有不同的 <Counter /> JSX 标签：
// 相同位置的不同组件会使 state 重置


// 只要在相同位置渲染的是相同组件， React 就会保留状态。
//     state 不会被保存在 JSX 标签里。它与你在树中放置该 JSX 的位置相关联。
//     你可以通过为一个子树指定一个不同的 key 来重置它的 state。
// 不要嵌套组件的定义，否则你会意外地导致 state 被重置。


// ref 是一种脱围机制，用于保留不用于渲染的值。 你不会经常需要它们。
// ref 是一个普通的 JavaScript 对象，具有一个名为 current 的属性，你可以对其进行读取或设置。
// 你可以通过调用 useRef Hook 来让 React 给你一个 ref。
// 与 state 一样，ref 允许你在组件的重新渲染之间保留信息。
// 与 state 不同，设置 ref 的 current 值不会触发重新渲染。
// 不要在渲染过程中读取或写入 ref.current。这使你的组件难以预测。


//     将 ref 视为脱围机制。当你使用外部系统或浏览器 API 时，ref 很有用。如果你很大一部分应用程序逻辑和数据流都依赖于 ref，你可能需要重新考虑你的方法。
//     不要在渲染过程中读取或写入 ref.current。 如果渲染过程中需要某些信息，请使用 state 代替。由于 React 不知道 ref.current 何时发生变化，
// 即使在渲染时读取它也会使组件的行为难以预测。（唯一的例外是像 if (!ref.current) ref.current = new Thing() 这样的代码，它只在第一次渲染期间设置一次 ref。）

// 何时使用 ref

// 通常，当你的组件需要“跳出” React 并与外部 API 通信时，你会用到 ref —— 通常是不会影响组件外观的浏览器 API。以下是这些罕见情况中的几个：

//     存储 timeout ID
//     存储和操作 DOM 元素，我们将在 下一页 中介绍
//     存储不需要被用来计算 JSX 的其他对象。

// 如果你的组件需要存储一些值，但不影响渲染逻辑，请选择 ref。

export default function Scoreboard() {
    const [isPlayerA, setIsPlayerA] = useState(true);
    const myRef = useRef(null);
    let countRef = useRef(0);
    const inputRef = useRef(null);

    function handleClick1() {
        inputRef.current.focus();
    }
    function handleClick() {
        // 这样并未重新渲染组件！
        countRef.current = countRef.current + 1;
    }
    return (
        <div>
            <input ref={inputRef} />
            <button onClick={handleClick1}>
                聚焦输入框
            </button>
            <div ref={myRef}></div>
            /**// 你可以使用任意浏览器 API，例如：  myRef.current.scrollIntoView(); */

            <button onClick={handleClick}>
                你点击了 {countRef.current} 次
            </button>
            /* // 相同位置的相同组件会使得 state 被保留下来 */
            {isPlayerA ? (
                <Counter person="Taylor" />
            ) : (
                <Counter person="Sarah" />
            )}

            /* // 不同位置的组件将state重置 */
            {isPlayerA &&
                <Counter person="Taylor" />
            }
            {!isPlayerA &&
                <Counter person="Sarah" />
            }

            /* // 添加key使同位置组件将state重置 */
            {isPlayerA ? (
                <Counter person="Taylor" key="Taylor" />
            ) : (
                <Counter person="Sarah" key="Sarah" />
            )}
            <button onClick={() => {
                setIsPlayerA(!isPlayerA);
            }}>
                下一位玩家！
            </button>
        </div>
    );
}

function Counter({ person }) {
    const [score, setScore] = useState(0);
    const [hover, setHover] = useState(false);

    let className = 'counter';
    if (hover) {
        className += ' hover';
    }

    return (
        <div
            className={className}
            onPointerEnter={() => setHover(true)}
            onPointerLeave={() => setHover(false)}
        >
            <h1>{person} 的分数：{score}</h1>
            <button onClick={() => setScore(score + 1)}>
                加一
            </button>
        </div>
    );
}